import { NodeTypes } from "./ast.js";
import {
  CREATE_ELEMENT_BLOCK,
  CREATE_ELEMENT_VNODE,
  FRAGMENT,
  OPEN_BLOCK,
  TO_DISPLAY_STRING,
  createCallExpression,
  createElementCall,
} from "./runtime-helpers.js";

function transformElement(node, context) {
  if (node.type === NodeTypes.ELEMENT) {
    let vnodeTag = `'${node.tag}'`; // 'div'
    let vnodeProps = node.props;
    let vnodeChildren = null;
    let properties = [];
    for (let i = 0; i < vnodeProps.length; i++) {
      properties.push({
        key: vnodeProps[i].name,
        value: vnodeProps[i].value.content,
      });
    }
    let propsExpression;
    if (vnodeProps.length > 0) {
      propsExpression = {
        properties,
        type: NodeTypes.JS_OBJECT_EXPRESSION,
      };
    }
    // 针对儿子的情况做处理, 有一个儿子直接用这个儿子
    if (node.children.length == 1) {
      vnodeChildren = node.children[0];
    } else {
      if (node.children) vnodeChildren = node.children;
    }
    node.codegenNode = createElementCall(
      context,
      vnodeTag,
      propsExpression,
      vnodeChildren
    );
  }
}

function isText(node) {
  return node.type === NodeTypes.TEXT || node.type === NodeTypes.INTERPOLATION;
}
function transformText(node, context) {
  if (node.type == NodeTypes.ELEMENT || node.type == NodeTypes.ROOT) {
    // element

    // 我们在处理的时候 是遇到这个节点就处理 还是等这个节点中的儿子都处理完了再处理
    return () => {
      // 退出函数 在元素的退出函数中处理所有的子节点

      let hasText = false; // 默认无文本
      let container = null;
      let children = node.children;
      for (let i = 0; i < children.length; i++) {
        // 先看前一个
        let child = children[i];
        if (isText(child)) {
          // 再看后一个
          hasText = true;
          for (let j = i + 1; j < children.length; j++) {
            const next = children[j];
            if (isText(next)) {
              if (!container) {
                container = children[i] = {
                  type: NodeTypes.COMPOUND_EXPRESSION,
                  children: [child],
                };
              }
              container.children.push("+", next);
              children.splice(j, 1);
              j--;
            } else {
              container = null; // 如果没有文本 清空容器
              break;
            }
          }
        }
      }
      // 如果只有一个儿子 不需要循环处理，可以直接采用innerHTML的方式 ， 如果没有文本也不用管了
      if (children.length === 1 || !hasText) {
        return;
      }
      for (let i = 0; i < children.length; i++) {
        const child = children[i];
        const args = [];
        if (isText(child) || NodeTypes.COMPOUND_EXPRESSION == child.type) {
          args.push(child);
          if (child.type !== NodeTypes.TEXT) {
            // 复合表达式
            args.push(PatchFlags.TEXT + "");
          }
          children[i] = {
            // createTextVnode
            type: NodeTypes.TEXT_CALL,
            content: child, // createTextVnode(内容，1)
            codegenNode: createCallExpression(context, args),
          };
        }
      }
    };
  }
}
function transformExpression(node, context) {
  // 元素 -》 表达式 -》 内容_toDisplayString
  if (node.type === NodeTypes.INTERPOLATION) {
    // 文本直接增加_ctx.xxx
    node.content.content = "_ctx." + node.content.content;
  }
}

function createContext(node) {
  const context = {
    currentNode: node,
    parent: null,
    helpers: new Map(),
    helper(name) {
      const c = context.helpers.get(name) || 0;
      context.helpers.set(name, c + 1);
      return name;
    },
    // 处理方法，看哪个节点能命中这个处理方法，做相应的处理
    nodeTransformFns: [transformElement, transformText, transformExpression],
    removeHelper(name) {
      let c = context.helpers.get(name);
      if (c) {
        c = c - 1;
        if (c == 0) {
          context.helpers.delete(name);
        } else {
          context.helpers.set(name, c);
        }
      }
      return name;
    },
  };
  return context;
}

function traverseNode(node, context) {
  // 遍历这棵语法树，，目的是对每个节点操作
  const fns = context.nodeTransformFns;
  const exitFns = [];
  for (let i = 0; i < fns.length; i++) {
    let exit = fns[i](node, context); // 进入当前节点
    exit && exitFns.push(exit);
  }

  switch (node.type) {
    case NodeTypes.ROOT:
    case NodeTypes.ELEMENT:
      for (let i = 0; i < node.children.length; i++) {
        context.parent = node;
        traverseNode(node.children[i], context); // 进入到子节点
      }
    case NodeTypes.INTERPOLATION:
      context.helper(TO_DISPLAY_STRING);
      break;
  }
  context.currentNode = node;
  // 子节点处理完毕
  let len = exitFns.length;
  while (len--) {
    exitFns[len]();
  }
}

function convertRoot(ast, context) {
  let children = ast.children;
  if (children.length === 1) {
    const child = children[0]; // createElementVnode x createElementBlock
    if (child.type === NodeTypes.ELEMENT) {
      ast.codegenNode = child.codegenNode; // 用元素的信息保留起来
      ast.codegenNode.isBlock = true; // 此节点是block节点
      context.removeHelper(CREATE_ELEMENT_VNODE);
      context.helper(OPEN_BLOCK);
      context.helper(CREATE_ELEMENT_BLOCK);
    } else {
      ast.codegenNode = child;
    }
  } else {
    // 多个儿子 生成一个block 并且是fragment
    if (children.length > 0) {
      ast.codegenNode = createElementCall(
        context,
        context.helper(FRAGMENT),
        undefined,
        ast.children
      );
      context.helper(OPEN_BLOCK);
      context.helper(CREATE_ELEMENT_BLOCK);
      ast.codegenNode.isBlock = true;
    }
  }
}

export function transform(ast) {
  const context = createContext(ast);
  traverseNode(ast, context);
  convertRoot(ast, context);
  ast.helpers = [...context.helpers.keys()];
}
